package com.bonc.ioc.util;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author ：liyy
 * @date ：Created in 2020/3/24 17:25
 * @description：用于登录验证的切面
 * @modified By：
 * @version: V1.0
 */
public class TokenUtil {

    /**
     * 编码密码,可自定义
     */
    private static final String ENCODED_PASSWORD = "ouyangjun";

    /**
     * Token校验信息，暂时放到内存中，后续可以考虑存储到Redis中
     */
    private static Map<String, String> MAP_TOKENS = new HashMap<String, String>();

    /**
     * token有效期(秒)
     */
    private static final int VALID_TIME = 60 * 60 * 2;

    /**
     * token校验方式-非法
     */
    public static final String TOKEN_ERROR = "F";

    /**
     * token校验方式-过期
     */
    public static final String TOKEN_OVERDUE = "G";

    /**
     * token校验方式-失效
     */
    public static final String TOKEN_FAILURE = "S";


    /**
     * 编码
     *
     * @param str
     * @return
     */
    public static String encoded(String str) {
        return strToHex(encodedString(str, ENCODED_PASSWORD));
    }

    /**
     * 转换
     *
     * @param str
     * @param password
     * @return
     */
    private static String encodedString(String str, String password) {
        char[] pwd = password.toCharArray();
        int pwdLen = pwd.length;

        char[] strArray = str.toCharArray();
        for (int i = 0; i < strArray.length; i++) {
            strArray[i] = (char) (strArray[i] ^ pwd[i % pwdLen] ^ pwdLen);
        }
        return new String(strArray);
    }

    private static String strToHex(String s) {
        return bytesToHexStr(s.getBytes());
    }

    private static String bytesToHexStr(byte[] bytesArray) {
        StringBuilder builder = new StringBuilder();
        String hexStr;
        for (byte bt : bytesArray) {
            hexStr = Integer.toHexString(bt & 0xFF);
            if (hexStr.length() == 1) {
                builder.append("0");
                builder.append(hexStr);
            } else {
                builder.append(hexStr);
            }
        }
        return builder.toString();
    }

    /**
     * 解码
     *
     * @param str
     * @return
     */
    public static String decoded(String str) {
        String hexStr = null;
        try {
            hexStr = hexStrToStr(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (hexStr != null) {
            hexStr = encodedString(hexStr, ENCODED_PASSWORD);
        }
        return hexStr;
    }

    private static String hexStrToStr(String hexStr) {
        return new String(hexStrToBytes(hexStr));
    }

    private static byte[] hexStrToBytes(String hexStr) {
        String hex;
        int val;
        byte[] btHexStr = new byte[hexStr.length() / 2];
        for (int i = 0; i < btHexStr.length; i++) {
            hex = hexStr.substring(2 * i, 2 * i + 2);
            val = Integer.valueOf(hex, 16);
            btHexStr[i] = (byte) val;
        }
        return btHexStr;
    }


    /**
     * 生成token,该token长度不一致,如需一致,可自行MD5或者其它方式加密一下
     * 该方式的token只存在磁盘上,如果项目是分布式,最好用redis存储
     *
     * @param str: 该字符串可自定义,在校验token时要保持一致
     * @return
     */
    public static String getToken(String str) {
        String token = TokenUtil.encoded(getCurrentTime() + "," + str);
        MAP_TOKENS.put(str, token);
        return token;
    }

    /**
     * 校验token的有效性
     *
     * @param token
     * @return
     */
    public static String checkToken(String token) {
        if (token == null) {
            return TOKEN_ERROR;
        }
        try {
            String[] tArr = TokenUtil.decoded(token).split(",");
            int size = 2;
            if (tArr.length != size) {
                return TOKEN_ERROR;
            }
            // token生成时间戳
            int tokenTime = Integer.parseInt(tArr[0]);
            // 当前时间戳
            int currentTime = getCurrentTime();
            if (currentTime - tokenTime < VALID_TIME) {
                String tokenStr = tArr[1];
                String mToken = MAP_TOKENS.get(tokenStr);
                if (mToken == null) {
                    return TOKEN_OVERDUE;
                } else if (!mToken.equals(token)) {
                    return TOKEN_FAILURE;
                }
                return tokenStr;
            } else {
                return TOKEN_OVERDUE;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return TOKEN_ERROR;
    }

    /**
     * 获取当前时间戳（10位整数）
     */
    public static int getCurrentTime() {
        return (int) (System.currentTimeMillis() / 1000);
    }

    /**
     * 移除过期的token
     */
    public static void removeInvalidToken() {
        int currentTime = getCurrentTime();
        for (Map.Entry<String, String> entry : MAP_TOKENS.entrySet()) {
            String[] tArr = TokenUtil.decoded(entry.getValue()).split(",");
            int tokenTime = Integer.parseInt(tArr[0]);
            if (currentTime - tokenTime > VALID_TIME) {
                MAP_TOKENS.remove(entry.getKey());
            }
        }
    }
}
